// Triangle.cpp
// Our first OpenGL program that will just draw a triangle on the screen.

#include <stdafx.h>
#include <GLTools.h>            // OpenGL toolkit
#include <GLFrame.h>
#include <GLFrustum.h>
#include <GLBatch.h>
#include <GLMatrixStack.h>
#include <GLGeometryTransform.h>
#ifdef __APPLE__
#include <glut/glut.h>          // OS X version of GLUT
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>            // Windows FreeGlut equivalent
#include "triangle.h"
#endif

#include <StopWatch.h>

//GLFrame frame;
GLFrame cameraFrame;
GLFrustum frustum;
GLuint shader;
CStopWatch timer;

int MVPMatrixLocation;


///////////////////////////////////////////////////////////////////////////////
// Window has changed size, or has just been created. In either case, we need
// to use the window dimensions to set the viewport and the projection matrix.

void ChangeSize(int w, int h) {
    glViewport(0, 0, w, h);
	frustum.SetPerspective(50.0f, w/h, 0.1f, 1000.0f);
}


void SetUpFrame(GLFrame &frame,const M3DVector3f origin,
				const M3DVector3f forward,
				const M3DVector3f up) {
					frame.SetOrigin(origin);
					frame.SetForwardVector(forward);
M3DVector3f side,oUp;
m3dCrossProduct3(side,forward,up);
m3dCrossProduct3(oUp,side,forward);
frame.SetUpVector(oUp);
frame.Normalize();

}

void LookAt(GLFrame &frame, const M3DVector3f eye,
        const M3DVector3f at,
        const M3DVector3f up) {
    M3DVector3f forward;
    m3dSubtractVectors3(forward, at, eye);
    SetUpFrame(frame, eye, forward, up);
}

///////////////////////////////////////////////////////////////////////////////
// This function does any needed initialization on the rendering context.
// This is the first opportunity to do any OpenGL related tasks.

void SetupRC() {
	

    // Blue background
    glClearColor(0.0f, 0.0f, 1.0f, 1.0f);

    shader = gltLoadShaderPairWithAttributes("vshader.vp", "fshader.fp",
            2, GLT_ATTRIBUTE_VERTEX, "vVertex", GLT_ATTRIBUTE_COLOR, "vColor");
    fprintf(stdout, "GLT_ATTRIBUTE_VERTEX : %d\nGLT_ATTRIBUTE_COLOR : %d \n",
            GLT_ATTRIBUTE_VERTEX, GLT_ATTRIBUTE_COLOR);


	MVPMatrixLocation=glGetUniformLocation(shader,"MVPMatrix");
	if(MVPMatrixLocation==-1)
	{
		fprintf(stderr,"uniform MVPMatrix could not be found\n");
	}

	M3DVector3f eye = {3.0f, 3.0f, 10.0f};
	M3DVector3f at = {0.0f, 0.0f, 0.0f};
	M3DVector3f up = {0.0f, 0.0f, 1.0f};
	LookAt(cameraFrame, eye, at, up);


	glFrontFace(GL_CW);
	glEnable( GL_DEPTH_TEST );
	//glEnable( GL_CULL_FACE );

	glEnable( GL_BLEND );
	glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );


}
void rysujTrojkat()
{

    glBegin(GL_TRIANGLES);

	static float scale =1.f;


	/////////podstawa
	glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 0.0, 1.0, 0.0);
	glVertex3f(scale * -0.5f,scale * -0.5f,scale *.0f);
    glVertex3f(scale *-0.5f,scale * 0.5f, scale *0.0);
    glVertex3f(scale *0.5f,scale * -0.5f,scale * .0f);

	glVertex3f(scale * 0.5f,scale * 0.5f,scale *.0f);
    glVertex3f(scale *-0.5f,scale * 0.5f, scale *0.0);
    glVertex3f(scale *0.5f,scale * -0.5f,scale * .0f);
	//// koniec podstawa
	///gorna
	glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 1.0, 0.0, 0.0);
	glVertex3f(scale * 0.5f,scale * 0.5f,scale *.0f);
    glVertex3f(scale *-0.5f,scale * 0.5f, scale *0.0);
    glVertex3f(scale *0.f,scale * 0.f,scale * 2.0f);


	///prawa
	glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 0.0, 0.5, .5);
	glVertex3f(scale * 0.5f,scale * 0.5f,scale *.0f);
    glVertex3f(scale *0.5f,scale * -0.5f, scale *0.0);
    glVertex3f(scale *0.f,scale * 0.f,scale * 2.0f);

	///dolna
	glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 0.5, 0.5, .5);
	glVertex3f(scale * -0.5f,scale * -0.5f,scale *.0f);
    glVertex3f(scale *0.5f,scale * -0.5f, scale *0.0);
    glVertex3f(scale *0.f,scale * 0.f,scale * 2.0f);


	///lewa
	glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 1, 1, .5);
	glVertex3f(scale * -0.5f,scale * -0.5f,scale *.0f);
    glVertex3f(scale *-0.5f,scale * 0.5f, scale *0.0);
    glVertex3f(scale *0.f,scale * 0.f,scale * 2.0f);

    glEnd();
}


void rysujSiatke()
{

    glBegin(GL_LINES);

	static float scale =.5f;
	
	for(int i=0;i<11;++i)
	{
		glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 0.0, 1.0, 0.0);
		glVertex3f((scale * (-10.f)) + i ,scale *10.f,scale *.0f);
		glVertex3f((scale * -10.f) + i ,scale * (-10.f),scale *.0f);
	}

	for(int i=0;i<11;++i)
	{
		glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 0.0, 1.0, 0.0);
		glVertex3f(scale *10.f,(scale * (-10.f)) + i ,scale *.0f);
		glVertex3f(scale * (-10.f),(scale * -10.f) + i ,scale *.0f);
	}


    glEnd();
}






///////////////////////////////////////////////////////////////////////////////
// Called to draw scene

void RenderScene(void) {
    // Clear the window with current clearing color
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

   
    glUseProgram(shader);



	GLMatrixStack stack;
	
	stack.PushMatrix();
	stack.LoadMatrix(frustum.GetProjectionMatrix());



	M3DMatrix44f VPMatrix;
	M3DMatrix44f mCamera;
	M3DMatrix44f mFrame;

	cameraFrame.GetCameraMatrix(mCamera);
	
	stack.MultMatrix(mCamera);

	stack.PushMatrix();
	glUniformMatrix4fv(MVPMatrixLocation,1,GL_FALSE,stack.GetMatrix());
	rysujSiatke();

	stack.Translate(0.0f,0.0f,-1.f);
	glUniformMatrix4fv(MVPMatrixLocation,1,GL_FALSE,stack.GetMatrix());
	rysujTrojkat();

	stack.PopMatrix();
	stack.Translate(0.0f,4.0f,0.f);
	glUniformMatrix4fv(MVPMatrixLocation,1,GL_FALSE,stack.GetMatrix());
	rysujTrojkat();

	stack.PushMatrix();


	stack.PopMatrix();
	stack.Translate(2.0f,0.0f,0.f);
	stack.Scale(2,2,2);
	stack.Rotate(45,0,0,1);
	glUniformMatrix4fv(MVPMatrixLocation,1,GL_FALSE,stack.GetMatrix());
	rysujTrojkat();
/*
	M3DMatrix44f mM3,mM4,wyn;
	m3dTranslationMatrix44(mM3,2.0f,0.0f,0.f);
	m3dScaleMatrix44(mM4,2,2,2);
	m3dMatrixMultiply44(wyn,mM4,mM3);

	m3dMatrixMultiply44(mMVP,VPMatrix,wyn);

	glUniformMatrix4fv(MVPMatrixLocation,1,GL_FALSE,mMVP);


	rysujTrojkat();

*/


    // Perform the buffer swap to display back buffer
    glutSwapBuffers();

	M3DVector3f at={0,0,0};
	M3DVector3f up={0,0,1};
	M3DVector3f eye;
	float angle = timer.GetElapsedSeconds()*3.14159f /3.f;
	eye[0]=6.8f*cos(angle);
	eye[1]=6.0f*sin(angle);
	eye[2]=25.0f; 
	LookAt(cameraFrame,eye,at,up);

glutPostRedisplay();
}


///////////////////////////////////////////////////////////////////////////////
// Main entry point for GLUT based programs

int main(int argc, char* argv[]) {
  

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
    glutInitWindowSize(800, 800);
    glutCreateWindow("Triangle");
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);

    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    }

    SetupRC();

    glutMainLoop();
    return 0;
}

triangle::triangle(void)
{
}
